﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Text;

namespace Cyss.Core
{
    /// <summary>
    /// 转换属性对象
    /// </summary>
    public class CastProperty
    {
        /// <summary>
        /// 源属性
        /// </summary>
        public PropertyAccessorHandler SourceProperty
        {
            get;
            set;
        }
        /// <summary>
        /// 目标属性
        /// </summary>
        public PropertyAccessorHandler TargetProperty
        {
            get;
            set;
        }
    }

    /// <summary>
    /// 属性访问器
    /// </summary>
    public class PropertyAccessorHandler
    {
        /// <summary>
        /// 以一个属性对象初始化类
        /// </summary>
        /// <param name="propInfo">性对象</param>
        public PropertyAccessorHandler(PropertyInfo propInfo)
        {
            this.PropertyName = propInfo.Name;
            this.PropertyType = propInfo.PropertyType;
            //var obj = Activator.CreateInstance(classType);
            //var getterType = typeof(FastPropertyAccessor.GetPropertyValue<>).MakeGenericType(propInfo.PropertyType);
            //var setterType = typeof(FastPropertyAccessor.SetPropertyValue<>).MakeGenericType(propInfo.PropertyType);

            //this.Getter = Delegate.CreateDelegate(getterType, null, propInfo.GetGetMethod());
            //this.Setter = Delegate.CreateDelegate(setterType, null, propInfo.GetSetMethod());
            if (propInfo.CanRead)
                this.Getter = propInfo.GetValue;

            if (propInfo.CanWrite)
                this.Setter = propInfo.SetValue;
        }
        /// <summary>
        /// 属性名称
        /// </summary>
        public string PropertyName { get; set; }

        public Type PropertyType { set; get; }
        /// <summary>
        /// Get访问器
        /// </summary>
        public Func<object, object[], object> Getter { get; private set; }
        /// <summary>
        /// Set访问器
        /// </summary>
        public Action<object, object, object[]> Setter { get; private set; }







    }

    public delegate TResult MyFunc<TResult>();

    public delegate TResult MyFunc<T, TResult>(T arg);

    public delegate TResult MyFunc<T1, T2, TResult>(T1 arg1, T2 arg2);

    public delegate void MyAction();

    public delegate void MyAction<T1, T2>(T1 arg1, T2 arg2);

    public delegate void MyAction<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);

    public interface INamedMemberAccessor
    {
        Type PropertyType { get; }
        object GetValue(object instance);
        void SetValue(object instance, object newValue);

        bool CanRead { get; }

        bool CanWrite { get; }


        string ProjectName { get; }

        string ProjectDisplayName { get; }


        string DeclaringTypeName {  get; }
    }


    public class PropertyAccessor<T, P> : INamedMemberAccessor
    {
        private MyFunc<T, P> GetValueDelegate;
        private MyAction<T, P> SetValueDelegate;
        private Type _PropertyType;
        private bool _CanRead;
        private bool _CanWrite;
        private string _ProjectName;
        private string _ProjectDisplayName;
        private string _DeclaringTypeName;
        public PropertyAccessor(Type type, string propertyName)
        {
            var propertyInfo = type.GetProperty(propertyName);
            if (propertyInfo != null)
            {
                this._ProjectName = propertyInfo.Name;
                this._CanRead = propertyInfo.CanRead;
                this._CanWrite = propertyInfo.CanWrite;
                this._PropertyType = propertyInfo.PropertyType;
                this._ProjectDisplayName=propertyInfo.DeclaringType?.Name;
                var displayAttribute = propertyInfo.GetCustomAttribute<DisplayAttribute>() as DisplayAttribute;
                if (displayAttribute!=null)
                {
                    this._ProjectDisplayName=displayAttribute.Name;
                }
                if (propertyInfo.CanRead)
                    GetValueDelegate = (MyFunc<T, P>)Delegate.CreateDelegate(typeof(MyFunc<T, P>), propertyInfo.GetGetMethod());
                if (propertyInfo.CanWrite)
                    SetValueDelegate = (MyAction<T, P>)Delegate.CreateDelegate(typeof(MyAction<T, P>), propertyInfo.GetSetMethod());
            }
        }

        public object GetValue(object instance)
        {
            if (GetValueDelegate != null)
                return GetValueDelegate((T)instance);
            else
                return null;
        }

        public void SetValue(object instance, object newValue)
        {
            if (SetValueDelegate != null)
                SetValueDelegate((T)instance, (P)newValue);
        }


        public bool CanRead { get { return this._CanRead; } }

        public bool CanWrite { get { return this._CanWrite; } }

        public string ProjectName { get { return this._ProjectName; } }

        public Type PropertyType
        {
            get { return this._PropertyType; }
        }

        public string ProjectDisplayName
        {
            get { return this._ProjectDisplayName; }
        }

        public string DeclaringTypeName
        {
            get { return this.DeclaringTypeName; }
        }
    }
}
